/**
* @description {Class} uCalendar
* This is the main class of uCalendar.
*/

(function ($) {
    $.widget("mobile.uCalendar", $.mobile.widget, {

        /** Available options for the widget are specified here, along with default values. */
        defaultOption: {
            timeSlotUnit: 20,
            timeSlotHeight: 15,
            operatories: [{ name: "DoctorA"}],
        },
        /** Mandatory method - automatically called by jQuery Mobile to initialise the widget. */
        _create: function () {
            var inputElement = this.element;
            var option = $.extend(this.defaultOption, inputElement.data("options"));
            option.heightPerMinute = option.timeSlotHeight / option.timeSlotUnit;
            this.appliedOption = option;

            this.renderDayView(option);
            $(document).trigger("uCalendarcreate");
            $(inputElement).data("uCalendar", this.appliedOption);
            $(window).resize(function () {
                var height = document.documentElement.clientHeight - 90;
                $(".operatoryBody").height(height);

                var appointmentPanelWidth = document.documentElement.clientWidth - 78;
                $(".appointment").each(function (index, dayEventElement) {
                    var columnData = dayEventElement.dataset["column"].split("-");
                    var column = columnData[0];
                    var columnSpan = columnData[1];
                    var columnCnt = columnData[2];
                    var width = (columnSpan / columnCnt) * appointmentPanelWidth - 4;
                    $(dayEventElement).width(width);
                });
            });

        },
        redraw: function (options) {
            var option;
            if (this.appliedOption) {
                option = $.extend(this.appliedOption, options);
                option.heightPerMinute = option.timeSlotHeight / option.timeSlotUnit;
                this.appliedOption = option;
            }
            else {
                option = $.extend(this.defaultOption, options);
                option.heightPerMinute = option.timeSlotHeight / option.timeSlotUnit;
                this.defaultOption = option;
            }
            this.renderDayView(this.defaultOption);
        },

        renderDayView: function (option) {
            var calendarContainer = this.element;
            var html = [];
            //buildOperatoryHeader(html, option.operatories);            
            this.buildOperatoryBody(html, option);
            calendarContainer.html(html.join(""));
            html = null;
        },

        buildOperatoryHeader: function (html, operatories) {
            html.push("<div>");
            html.push("<table class=\"operatoryHeaderContainer\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
            html.push("<tr>");
            html.push("<th width=\"40\" style=\"background-color: Red\"></th>");

            var operatoryCnt = operatories.length;
            for (var i = 0; i < operatoryCnt; i++) {
                var operatory = operatories[i];
                html.push("<th scope=\"col\"><div class=\"operatoryHeaderContent\"><span>" + operatory.name + "</span></div></th>");
            }

            html.push("</tr>");
            html.push("</table>");
            html.push("</div>");
        },

        buildOperatoryBody: function (html, option) {
            //no height specified in options, we get page height.
            option.height = document.documentElement.clientHeight - 83;
            option.calendarHeight = option.heightPerMinute * 60 * 24; 
            html.push("<div style=\"overflow-y: visible; height: " + option.height + "px;\" class=\"operatoryBody\">");
            html.push("<table style=\"table-layout: fixed; width: 100%\" cellpadding=\"0\" cellspacing=\"0\">");
            html.push("<tr><td>");
            html.push("<table style=\"height: " + option.calendarHeight + "\" class=\"operatoryContainer\" cellpadding=\"0\" cellspacing=\"0\">");
            this.buildTimeSlot(html, option);
            this.buildOperatoryAreasPresenter(html, option);
            html.push("</table>");
            html.push("</tr></td>");
            html.push("</table>");
            html.push("</div>");
        },

        buildOperatoryAreasPresenter: function (html, option) {
            html.push("<tr>");
            this.buildDayLedger(html, option);

            var operatoryCnt = option.operatories.length;
            for (var i = 0; i < operatoryCnt; i++) {
                var operatory = option.operatories[i];
                this.buildOperatoryArea(html, operatory, option);
            }
            html.push("</tr>");
        },

        buildOperatoryArea: function (html, operatory, option) {
            html.push("<td class=\"resourcePanel\" ch=\"qkadd\">");
            html.push("<div style=\"margin-bottom: -", option.calendarHeight, "px; height: ", option.calendarHeight, "px\" class=\"appointmentPanel\">");
            //buildAppointmentPresenter(html, appointments);
            html.push("</div>");
            html.push("</td>");
        },

        buildDayLedger: function (html, option) {
            html.push("<td style=\"width: 45px\" class=\"dayLedger\">");
            var timeSlotUnit = option.timeSlotUnit;
            var timeSlotCnt = 60 / timeSlotUnit;
            var dayLedgerItemHeight = timeSlotCnt * option.timeSlotHeight - 1;
            for (var hour = 0; hour < 24; hour++) {
                html.push("<div class=\"dayLedgerItem\" style=\"height:", dayLedgerItemHeight, "px\">");
                html.push("<div class=\"dayLedgerMinuteTextWrapper\" style=\"height:", dayLedgerItemHeight, "\">");
                for (var timeSlotIndex = 1; timeSlotIndex <= timeSlotCnt; timeSlotIndex++) {
                    var minute = (timeSlotIndex - 1) * timeSlotUnit;
                    var minuteText = this.formatMinuteText(minute);
                    var className = timeSlotIndex == 1 ? "dayLedgerMinuteTextFirst"
                        : timeSlotIndex == timeSlotCnt ? "dayLedgerMinuteTextLast"
                        : "dayLedgerMinuteTextMiddle";
                    var lineHeight = option.timeSlotHeight - 1;
                    var style = "style=\"line-height:" + lineHeight + "px\"";

                    html.push("<div class=\"", className, "\" ", style, ">", minuteText, "</div>");
                }
                html.push("</div>");

                var hourText = this.fomatHourText(hour);
                html.push("<div class=\"dayLedgerHourText\" style=\"line-height:", dayLedgerItemHeight, "px\">", hourText, "</div>");

                html.push("</div>");
            }
            html.push("</td>");
        },

        buildTimeSlot: function (html, option) {
            html.push("<tr>");
            html.push("<td style=\"width: 45px;height:1px\"></td>");
            var operatoryCnt = option.operatories.length;

            html.push("<td colspan=\"" + operatoryCnt + "\">");
            html.push("<div class=\"timeSlotWrapper\"><div class=\"timeSlotContainer\">");

            var timeSlotCnt = 60 / option.timeSlotUnit;
            var timeSlotHeight = timeSlotCnt * option.timeSlotHeight - 1;
            for (var hour = 1; hour <= 24; hour++) {
                html.push("<div class=\"timeSlotGroup\" style=\"height:" + timeSlotHeight + "px\">");

                for (var timeSlotIndex = 1; timeSlotIndex <= timeSlotCnt; timeSlotIndex++) {
                    var className = timeSlotIndex == 1 ? "timeSlotFirst"
                        : timeSlotIndex == timeSlotCnt ? "timeSlotLast"
                        : "timeSlotMiddle";
                    var height = option.timeSlotHeight - 1;
                    var style = "style=\"height:" + height + "px\"";
                    html.push("<div class=\"", className, "\" ", style, "></div>");
                }

                html.push("</div>");
            }

            html.push("</div></div>");
            html.push("</tr>");
        },

        fomatHourText: function (h) {
            return h < 10 ? "0" + h : h;
        },

        formatMinuteText: function (m) {
            return m < 10 ? "0" + m : m;
        },

        /** Custom method to handle updates. */
        _update: function () {
            var inputElement = this.element;
            var opts = $.extend(this.options, inputElement.data("options"));

        },
        /* Externally callable method to force a refresh of the widget. */
        refresh: function () {
            alert("refresh");
            return this._update();
        },

        renderDayEvents: function (dayEvents) {
            var appointmentPanelWidth = document.documentElement.clientWidth - 78;
            var groupedDayEvents = this.groupDayEvents(dayEvents);
            var html = [];
            for (var groupIndex = 0; groupIndex < groupedDayEvents.length; groupIndex++) {
                var a = this.arrangeDayEvents(groupedDayEvents[groupIndex]);
                var columnCnt = a.columnCnt;
                var sortedDayEvents = a.dayEvents;
                var dayEventCnt = sortedDayEvents.length;

                for (var i = 0; i < dayEventCnt; i++) {
                    var dayEvent = sortedDayEvents[i];
                    var topOffset = dayEvent.startTime * this.appliedOption.heightPerMinute + 2;
                    //alert(topOffset);
                    var height = (dayEvent.endTime - dayEvent.startTime) * this.appliedOption.heightPerMinute - 6;
                    var left = (dayEvent.column - 1) * 100 / columnCnt;
                    var width = Math.floor((dayEvent.columnSpan / columnCnt) * appointmentPanelWidth) - 4;
                    html.push("<div style=\"width: ", width, "px;left: ", left, "%;top:", topOffset, ";height:", height, "px;\" data-column=\"", dayEvent.column + "-" + dayEvent.columnSpan + "-" + columnCnt, "\" class=\"appointment\">");

                    html.push("<div class=\"appointmentTitle\">", dayEvent.title, "</div>");
                    if(dayEvent.detailItems)
                    {
                        html.push("<ul>");
                        $(dayEvent.detailItems).each(function(index, value)
                        {
                            html.push("<li>", value, "</li>");
                        });
                        html.push("</ul>");
                        
                    }
//                    html.push("<br /><span>", dayEvent.column, "</span>-<span>", dayEvent.columnSpan, "</span>-<span>", columnCnt, "</span>");
                    html.push("</div>");
                }
            }

            var inputElement = this.element;
            var appointmentPanel = inputElement.find(".appointmentPanel");

            appointmentPanel.html(html.join(""));
            //alert(appointmentPanel.html());
        },

        groupDayEvents: function (dayEvents) {
            var sortedDayEvents = dayEvents.sort(this.compareDayEvent);
            var groupedDayEvents = [];
            for (var eventIndex = 0; eventIndex < dayEvents.length; eventIndex++) {
                var dayEvent = dayEvents[eventIndex];
                var hasFoundGroup = false;
                for (var groupIndex = 0; groupIndex < groupedDayEvents.length; groupIndex++) {
                    var eventGroup = groupedDayEvents[groupIndex];
                    for (var eventIndexInGroup = 0; eventIndexInGroup < eventGroup.length; eventIndexInGroup++) {
                        if (this.isDayEventOverlap(dayEvent, eventGroup[eventIndexInGroup])) {
                            eventGroup.push(dayEvent);
                            hasFoundGroup = true;
                            break;
                        }
                    }
                    if (hasFoundGroup) {
                        break;
                    }
                }
                if (!hasFoundGroup) {
                    var eventGroup = [dayEvent];
                    groupedDayEvents.push(eventGroup);
                }
            }
            return groupedDayEvents;
        },

        arrangeDayEvents: function (dayEvents) {
            var sortedDayEvents = dayEvents.sort(this.compareDayEvent);
            var dayEventsCnt = sortedDayEvents.length;
            var columnCnt = 1;
            var columnGroups = [];
            if (dayEventsCnt > 0) {
                sortedDayEvents[0].column = 1;
                var firstColumnGroup = [sortedDayEvents[0]];
                columnGroups.push(firstColumnGroup);
                for (var i = 1; i < dayEventsCnt; i++) {
                    var dayEvent = sortedDayEvents[i];
                    var columnGroupIndex = 0;
                    for (; columnGroupIndex < columnGroups.length; columnGroupIndex++) {
                        var isDayEventOverlapWithThisColumn = false;
                        var dayEventsAtPreviousColumn = columnGroups[columnGroupIndex];

                        for (var j = 0; j < dayEventsAtPreviousColumn.length; j++) {
                            if (this.isDayEventOverlap(dayEvent, dayEventsAtPreviousColumn[j])) {
                                isDayEventOverlapWithThisColumn = true;
                                break;
                            }
                        }
                        if (!isDayEventOverlapWithThisColumn) {
                            break;
                        }
                    }
                    dayEvent.column = columnGroupIndex + 1;
                    if (columnGroups.length > columnGroupIndex) {
                        columnGroups[columnGroupIndex].push(dayEvent);
                    }
                    else {
                        var columnGroup = [dayEvent];
                        columnGroups.push(columnGroup);
                    }
                } // end for
                columnCnt = columnGroups.length;
                var sortDayEventsByColumn = dayEvents.sort(this.compareDayEventByColumn);

                for (var i = 0; i < dayEventsCnt; i++) {
                    var dayEvent = sortedDayEvents[i];
                    dayEvent.columnSpan = 1;
                    for (var j = dayEvent.column; j < columnGroups.length; j++) {
                        var dayEventsAtNextColumn = columnGroups[j];
                        var isDayEventOverlapWithThisColumn = false;
                        for (var k = 0; k < dayEventsAtNextColumn.length; k++) {
                            if (this.isDayEventOverlap(dayEvent, dayEventsAtNextColumn[k])) {
                                isDayEventOverlapWithThisColumn = true;
                                break;
                            }
                        }
                        if (!isDayEventOverlapWithThisColumn) {
                            dayEvent.columnSpan++;
                        }
                        else {
                            break;
                        }
                    }
                } // end for
            }
            return {
                columnCnt: columnCnt,
                dayEvents: sortDayEventsByColumn
            }
        },
        compareDayEvent: function (dayEvent1, dayEvent2) {
            var result = dayEvent1.startTime - dayEvent2.startTime;
            if (result == 0) {
                result = dayEvent2.endTime - dayEvent1.endTime;
            }
            return result;
        },

        compareDayEventByColumn: function (dayEvent1, dayEvent2) {
            return dayEvent1.column - dayEvent2.column;
        },

        isDayEventOverlap: function (dayEvent1, dayEvent2) {
            //            alert("dayEvent1: startTime:" + dayEvent1.startTime + " endTime:" + dayEvent1.endTime);
            //            alert("dayEvent2: startTime:" + dayEvent2.startTime + " endTime:" + dayEvent2.endTime);
            var isOverlap = (dayEvent2.startTime > dayEvent1.startTime && dayEvent2.startTime < dayEvent1.endTime)
                || (dayEvent2.endTime > dayEvent1.startTime && dayEvent2.endTime < dayEvent1.endTime)
                || (dayEvent2.startTime <= dayEvent1.startTime && dayEvent2.endTime >= dayEvent1.endTime);
            //alert(isOverlap);
            return isOverlap;
        }
    });
    /* Handler which initialises all widget instances during page creation. */
    $(document).bind("pagecreate", function (e) {
        $(document).trigger("uCalendarbeforecreate");
        return $(":jqmData(role='uCalendar')", e.target).uCalendar();
    });
})(jQuery);

